package com.admin.sys.base.module.shiro;

import com.admin.sys.base.cache.service.SysCacheService;
import com.admin.sys.base.constant.AdminConst;
import com.admin.sys.base.module.menu.dao.SysMenuDao;
import com.admin.sys.base.module.menu.entity.SysMenu;
import com.admin.sys.base.module.office.dao.SysOfficeDao;
import com.admin.sys.base.module.office.entity.SysOffice;
import com.admin.sys.base.module.role.dao.SysRoleDao;
import com.admin.sys.base.module.role.entity.SysRole;
import com.admin.entity.SysUser;
import com.admin.service.SysUserService;
import com.admin.sys.utils.admin.ObjectUtils;
import com.admin.sys.utils.admin.ShiroUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户角色权限认证
 * 登录时获取用户所属角色，再通过角色获取所属角色权限。
 */
public class ShiroUserRealm extends AuthorizingRealm {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysRoleDao sysRoleDao;
    @Autowired
    private SysMenuDao sysMenuDao;
    @Autowired
    private SysOfficeDao sysOfficeDao;
    @Autowired
    private SysCacheService sysCacheService;

    public final static String REALM_NAME = "shiroCasRealm";
    public ShiroUserRealm(){
        setName(REALM_NAME);
    }

    /**
     * 登陆认证(登录时调用)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        String loginName = token.getUsername();
        ByteSource salt = ByteSource.Util.bytes(AdminConst.SALT);
        SysUser params = new SysUser();
        params.setLoginName(loginName);
        SysUser sysUser = sysUserService.get(params);
        if (ObjectUtils.isNull(sysUser)) {
            throw new UnknownAccountException();
        }
        if (sysUser.getDisabled() == 1) {
            throw new DisabledAccountException();
        }
        if (sysUser.getDisabled() == 3) {
            throw new AccountException();
        }
        //设置角色
        List<SysRole> roleList = sysRoleDao.findRolesListByUserId(sysUser.getId());
        sysUser.setRoleList(roleList);
        //设置部门
        SysOffice office = sysOfficeDao.selectById(sysUser.getOfficeId());
        sysUser.setOffice(office);
        //设置权限
        Set<SysMenu> menuSet = sysMenuDao.findPermissionsByUserId(sysUser.getId());
        Set<String> permsSet = new HashSet<>(menuSet.stream().map(SysMenu::getPermission).collect(Collectors.toList()));
        //设置缓存
        ShiroUtils.setSession(AdminConst.USER_INFO, sysUser);
        ShiroUtils.setSession(AdminConst.USER_PERMISSION, permsSet);
        ShiroUtils.setSession(AdminConst.USER_MENU, menuSet);//给日志匹配用
        sysCacheService.init();
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(sysUser, sysUser.getPassword(), salt, getName());
        return simpleAuthenticationInfo;
    }

    /**
     * 角色认证
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SysUser sysUser = (SysUser)principals.getPrimaryPrincipal();
        Set<String> permsSet = (Set<String>) ShiroUtils.getSession(AdminConst.USER_PERMISSION);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        List<String> collect = sysUser.getRoleList().stream().map(SysRole::getRoleCode).collect(Collectors.toList());
        Set<String> roleList = new HashSet<>(collect);
        info.setRoles(roleList);
        return info;
    }

}
